<template>
  <div class="viewport" ref="viewport" @scroll="scrollFn">
    <div class="scroll-bar" ref="scroll"> </div>   <!--其实就是用这个div把viewport撑大了-->
    <div class="scroll-list" :style="{transform:`translate3d(0,${offset}px,0)`}">
      <div v-for="item in visibleData" :key="items.id" ref="items">
        <slot :item="item"></slot>
      </div>
    </div>
  </div>
</template>

<script>    //   这个是虚拟列表插件
import { throttle } from "lodash";
export default {
  name: "virtual-list",
  props: {
    size: Number,
    remain:  Number,
    items:  Array,
    variable: Boolean,
  },
  data() {
    return {
      start: 0,
      end: this.remain,
      offset: 0,
      scrollFn: ''
    }
  },
  created() {
    this.scrollFn = throttle(this.handleScroll,200,{leading: false})
    // this.scrollFn = throttle(this.getStartIndex,200,{leading: false})
    // this.scrollFn = throttle(this.cacheList,200,{leading: false})
  },
  computed: {
    prevCount() {
      return Math.min(this.start, this.remain);
    },
    nextCount() {
      return Math.min(this.remain, this.items.length - this.end)
    },
    visibleData() {
      let start = this.start - this.prevCount;
      let end = this.end + this.nextCount + 8;
      return this.items.slice(start,end);
    }
  },
  mounted() {
    this.$refs.viewport.style.height = this.size * this.remain + 'px';
    this.$refs.scroll.style.height = this.items.length * this.size + 'px';  // 滚动条的长度
    this.cacheList();
  },
  updated() {
    this.$nextTick(() => {
      let nodes = this.$refs.items;
      if (!(nodes&&nodes.length > 0)) {
        return;
      }
      nodes.forEach(node => {
        let { height } = node.getBoundingClientRect();
        let id = node.getAttribute('vid') - 0;
        let oldHeight = this.positions[id].height;
        let val = oldHeight - height;
        if (val) {
          this.positions[id].height = height;
          this.positions[id].bottom = this.positions[id].bottom - val;
          for (let i = id + 1; i < this.positions.length; i++) {
            this.positions[i].top = this.positions[i-1].bottom;
            this.positions[i].bottom = this.positions[i].bottom - val;
          }
        }
      });
      this.$refs.scroll.style.height = Math.floor(this.positions[this.positions.length - 1].bottom) + 'px';
    })
  },
  methods: {
    cacheList() {
      this.positions = this.items.map((item, index) => ({
        height: this.size,
        top: index * this.size,
        bottom: (index + 1) * this.size
      }));
    },
    getStartIndex(value) {
      let start = 0;
      let end = this.positions.length -1;
      let temp = null;
      while(start <= end) {
        let middleIndex = Math.floor(parseInt((start + end)/2));
        let middleValue = this.positions[middleIndex].bottom;
        if(middleValue === value) {
          return middleIndex + 1;
        }else if(middleValue< value) {
          start = middleIndex + 1;
        }else if(middleValue > value) {
          if (temp === null || temp > middleIndex) {
            temp = middleIndex;
          }
          end = middleIndex - 1;
        }
      }
      return temp;
    },
    handleScroll() {
      let scrollTop = Math.floor(this.$refs.viewport.scrollTop);   // 当前滚过去的高度
      if (this.variable) {
        this.start = this.getStartIndex(scrollTop);
        this.end = this.start + this.remain;
        this.offset = this.positions[this.start - this.prevCount] ?
        this.positions[this.start - this.prevCount].top : 0;
        console.log(this.offset)
      }else {
        this.start = Math.floor(scrollTop / this.size);   //向下取整 3.5 -> 3
        // this.start = scrollTop / this.size;   //向下取整 3.5 -> 3
        this.end = this.start + this.remain;
        this.offset = this.start * this.size - this.size * this.prevCount;
      }
    }
  }
}
</script>

<style scoped>
.viewport {
  overflow-y: scroll;
  position: relative;
}
.scroll-list {
  /*background-color: #42b983;*/
  position: absolute;
  left: 0;
  top: 0;
  width: 80%;
}
.scroll-bar {
  /*background-color: #5a5e66;*/
  /*width: 80%;*/
}
</style>
